/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.andtinder.view;

import com.andtinder.AttrUtils;
import com.andtinder.model.Orientation;

import ohos.agp.components.AttrSet;
import ohos.agp.components.BaseItemProvider;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.database.DataSetSubscriber;
import ohos.app.Context;

import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;

/**
 * 卡片容器
 */
public abstract class BaseCardContainer extends ComponentContainer
        implements Component.LayoutRefreshedListener,
        Component.BindStateChangedListener,
        ComponentContainer.ArrangeListener {
    /**
     * DISORDERED_MAX_ROTATION_RADIANS
     */
    public static final double DISORDERED_MAX_ROTATION_RADIANS = Math.PI / 64;
    private static final String MAX_VISIBLE_NUM = "maxVisibleNum";
    private int defaultMaxVisible = 4;
    private int mMaxVisible;
    private final List<Component> mChildComponents = new ArrayList<>();
    private BaseItemProvider mProvider;
    private boolean mIsRegistered;
    private Orientation orientation;
    private SecureRandom random = new SecureRandom();

    private DataSetSubscriber subscriber = new DataSetSubscriber() {
        @Override
        public void onChanged() {
        }

        @Override
        public void onItemInserted(int position) {
            insertItem(position);
        }

        @Override
        public void onItemRemoved(int position) {
            removeItem(position);
        }

        @Override
        public void onItemRangeChanged(int positionStart, int itemCount) {
        }

        @Override
        public void onItemRangeInserted(int positionStart, int itemCount) {
        }

        @Override
        public void onItemRangeRemoved(int positionStart, int itemCount) {
        }
    };

    /**
     * 构造方法
     *
     * @param context 上下文
     */
    public BaseCardContainer(Context context) {
        this(context, null);
    }

    /**
     * 构造方法
     *
     * @param context 上下文
     * @param attrSet 自定义属性
     */
    public BaseCardContainer(Context context, AttrSet attrSet) {
        this(context, attrSet, null);
    }

    /**
     * 构造方法
     *
     * @param context 上下文
     * @param attrSet 自定义属性
     * @param styleName 风格样式
     */
    public BaseCardContainer(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        mMaxVisible = AttrUtils.getIntFromAttr(attrSet, MAX_VISIBLE_NUM, defaultMaxVisible);
        setArrangeListener(this);
        setBindStateChangedListener(this);
        setLayoutRefreshedListener(this);
    }

    @Override
    public void onComponentBoundToWindow(Component component) {
        if (mProvider != null && !mIsRegistered) {
            mIsRegistered = true;
            mProvider.addDataSubscriber(subscriber);
        }
    }

    @Override
    public void onComponentUnboundFromWindow(Component component) {
        if (mProvider != null && mIsRegistered) {
            mIsRegistered = false;
            mProvider.removeDataSubscriber(subscriber);
        }
    }

    @Override
    public Component getComponentAt(int index) {
        if (index < 0 || index >= mChildComponents.size()) {
            return null;
        }
        return mChildComponents.get(index);
    }

    @Override
    public boolean onArrange(int left, int top, int right, int bottom) {
        for (int i = 0; i < getChildCount(); i++) {
            Component childComponent = getComponentAt(i);
            if (childComponent != null) {
                childComponent.setContentPositionX((getWidth() - childComponent.getWidth()) / 2f);
                childComponent.setContentPositionY((getHeight() - childComponent.getHeight()) / 2f);
            }
        }
        return false;
    }

    /**
     * 获取当前被选中的item组件
     *
     * @return 被选中的组件
     */
    public abstract Component getSelectedComponent();

    /**
     * 获取适配器
     *
     * @return 适配器
     */
    public BaseItemProvider getItemProvider() {
        return mProvider;
    }

    /**
     * 设置适配器
     *
     * @param itemProvider 适配器
     */
    public void setItemProvider(BaseItemProvider itemProvider) {
        mProvider = itemProvider;
        if (mProvider != null && !mIsRegistered) {
            mIsRegistered = true;
            mProvider.addDataSubscriber(subscriber);
        }
        mChildComponents.clear();
        if (getChildCount() > 0) {
            removeAllComponents();
        }
        addAllItem();
    }

    private void addAllItem() {
        if (mProvider == null) {
            return;
        }
        for (int i = 0; i < mProvider.getCount(); i++) {
            boolean isAddToParent = false;
            Component childComponent = null;
            if (i < getChildCount()) {
                childComponent = getComponentAt(i);
            }
            if (childComponent == null) {
                isAddToParent = true;
            }
            childComponent = mProvider.getComponent(i, childComponent, this);
            if (isAddToParent) {
                mChildComponents.add(childComponent);
                if (getChildCount() < mMaxVisible) {
                    addComponent(childComponent, 0);
                }
                if (getOrientation() == Orientation.Disordered) {
                    childComponent.setRotation((float) Math.toDegrees(random.nextGaussian() * DISORDERED_MAX_ROTATION_RADIANS));
                }
            }
        }
    }

    private void insertItem(int position) {
        Component addComponent = mProvider.getComponent(position, null, this);
        mChildComponents.add(addComponent);
        for (int i = 0; i < mChildComponents.size(); i++) {
            mProvider.getComponent(i, mChildComponents.get(i), this);
        }
    }

    private void removeItem(int position) {
        if (position >= 0 && position < mChildComponents.size()) {
            Component removeComponent = mChildComponents.get(position);
            mChildComponents.remove(removeComponent);
            int childIndex = getChildIndex(removeComponent);
            if (childIndex >= 0) {
                removeComponentAt(childIndex);
            }
            int childCount = getChildCount();
            if (childCount < mMaxVisible && childCount < mChildComponents.size()) {
                addComponent(mChildComponents.get(getChildCount()), 0);
            }
        }
    }

    public Orientation getOrientation() {
        return orientation;
    }

    /**
     * set orientation
     *
     * @param orientation
     */
    public void setOrientation(Orientation orientation) {
        this.orientation = orientation;
    }
}
